/* 
 * FileHandler.java      1.00    2008-01-11 
 *
 * Copyright (c) 2010 monolist. All Rights Reserved.
 * 
 * This software is the confidential and proprietary information
 * of monolist.  You shall not disclose such Confidential Information
 * and shall use it only in accordance with the terms of the license agreement
 * you entered into with monolist.
 */
package doit.framework.servlet;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.log4j.Logger;
import org.directwebremoting.servlet.HttpConstants;
import org.directwebremoting.util.IdGenerator;
import org.directwebremoting.util.JavascriptUtil;
import org.directwebremoting.util.LocalUtil;

import doit.framework.util.Constants;

/**
 * <pre>
 * system      : 공통
 * menu        : 공통
 * source      : FileHandler.java
 * description : 공통 파일 핸들러
 * </pre> 
 * @version
 * <pre> 
 * 1.0  2008-01-11  monolist  최초 작성
 * 1.1  
 * </pre>
 */

@SuppressWarnings("unchecked")

public class FileHandler
{
    private boolean dynamic = false;
    
//    private boolean isUpToDate = false;
    
    protected final Map scriptCache = new HashMap();
    
    protected final Map cssCache = new HashMap();
    
    protected static final String PARAM_SCRIPT_ALLOWGET = "${allowGetForSafariButMakeForgeryEasier}";

    protected static final String PARAM_SCRIPT_POLLXHR = "${pollWithXhr}";

    protected static final String PARAM_SCRIPT_SESSIONID = "${scriptSessionId}";

    protected static final String PARAM_SCRIPT_COOKIENAME = "${sessionCookieName}";

    protected static final String PARAM_SCRIPT_TAG_PROTECTION = "${scriptTagProtection}";

    protected static final String PARAM_DEFAULT_PATH = "${defaultPath}";

    protected String sessionCookieName = "JSESSIONID";
    
    protected int compressionLevel = JavascriptUtil.LEVEL_DEBUGGABLE;

    protected IdGenerator generator = new IdGenerator();
    
    private String scriptTagProtection = Constants.SCRIPT_TAG_PROTECTION;

    protected int pageIdLength = 16;
    
    private boolean allowGetForSafariButMakeForgeryEasier = false;

    private String pollWithXhr = "false";
    
    private String overridePath = null;
    
    private static final long servletContainerStartTime;
    
    protected boolean scriptCompressed = false;
    
    private static final String etag;
    
    private static final Logger log = Logger.getLogger(FileHandler.class);

    static {
        long now = System.currentTimeMillis();
        servletContainerStartTime = now - (now % 1000);

        etag = "\"" + servletContainerStartTime + '\"';
    }
    
	public FileHandler() {
    }
	
    public void handle(HttpServletRequest request, HttpServletResponse response, String filePath) throws IOException
    {
        if (dynamic) {
            response.setHeader("pragma", "public");
            response.setHeader("Expires", "0");
            response.setHeader("Cache-Control", "must-revalidate, post-check=0, pre-check=0");
        }

        if (!dynamic && isUpToDate(request, filePath)) {
            response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
            return;
        }

        String output;

        synchronized (scriptCache)
        {
        	output = (String) scriptCache.get(filePath);
            if (output == null)
            {
                StringBuffer buffer = new StringBuffer();

                String resource = Constants.FILE_TIMS_JS + filePath;
                InputStream raw = getClass().getResourceAsStream(resource);
                
                if (raw == null) {
                    throw new IOException("Failed to find resource: " + resource);
                }
                BufferedReader in = new BufferedReader(new InputStreamReader(raw, "UTF-8"));
                while (true) {
                    String line = in.readLine();
                    if (line == null) {
                        break;
                    }
                    if (dynamic) {
                        if (line.indexOf(PARAM_SCRIPT_COOKIENAME) != -1) {
                            line = LocalUtil.replace(line, PARAM_SCRIPT_COOKIENAME, sessionCookieName);
                        }

                        if (line.indexOf(PARAM_SCRIPT_POLLXHR) != -1) {
                            line = LocalUtil.replace(line, PARAM_SCRIPT_POLLXHR, pollWithXhr);
                        }

                        if (line.indexOf(PARAM_SCRIPT_SESSIONID) != -1) {
                            line = LocalUtil.replace(line, PARAM_SCRIPT_SESSIONID, generator.generateId(pageIdLength));
                        }

                        if (line.indexOf(PARAM_SCRIPT_ALLOWGET) != -1) {
                            line = LocalUtil.replace(line, PARAM_SCRIPT_ALLOWGET, String.valueOf(allowGetForSafariButMakeForgeryEasier));
                        }

                        if (line.indexOf(PARAM_SCRIPT_TAG_PROTECTION) != -1) {
                            line = LocalUtil.replace(line, PARAM_SCRIPT_TAG_PROTECTION, scriptTagProtection);
                        }

                        if (line.indexOf(PARAM_DEFAULT_PATH) != -1) {
                            String path = request.getContextPath() + request.getServletPath();
                            if (overridePath != null) {
                                path = overridePath;
                            }
                            line = LocalUtil.replace(line, PARAM_DEFAULT_PATH, path);
                        }
                    }

                    buffer.append(line);
                    buffer.append('\n');
                }

                output = buffer.toString();

                if (!dynamic) {
                    scriptCache.put(filePath, output);
                }
            }
        }

        response.setContentType(Constants.MIME_JS);
        response.setDateHeader(HttpConstants.HEADER_LAST_MODIFIED, servletContainerStartTime);
        response.setHeader(HttpConstants.HEADER_ETAG, etag);

        PrintWriter out = response.getWriter();
        out.println(output);
    }
    
    public void handleCss(HttpServletRequest request, HttpServletResponse response, String filePath) throws IOException
    {
        if (dynamic) {
            response.setHeader("pragma", "public");
            response.setHeader("Expires", "0");
            response.setHeader("Cache-Control", "must-revalidate, post-check=0, pre-check=0");
        }

        if (!dynamic && isUpToDate(request, filePath)) {
            response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
            return;
        }

        String output;

        synchronized (cssCache)
        {
        	output = (String) cssCache.get(filePath);
            if (output == null)
            {
                StringBuffer buffer = new StringBuffer();

                String resource = Constants.FILE_TIMS_CSS + filePath;
                InputStream raw = getClass().getResourceAsStream(resource);
                if (raw == null) {
                    throw new IOException("Failed to find resource: " + resource);
                }
                BufferedReader in = new BufferedReader(new InputStreamReader(raw));
                while (true) {
                    String line = in.readLine();
                    if (line == null) {
                        break;
                    }
                    if (dynamic) {
                        if (line.indexOf(PARAM_DEFAULT_PATH) != -1) {
                            String path = request.getContextPath() + request.getServletPath();
                            if (overridePath != null) {
                                path = overridePath;
                            }
                            line = LocalUtil.replace(line, PARAM_DEFAULT_PATH, path);
                        }
                    }

                    buffer.append(line);
                    buffer.append('\n');
                }

                output = buffer.toString();

                if (!dynamic) {
                	cssCache.put(filePath, output);
                }
            }
        }

        response.setContentType(Constants.MIME_CSS);
        response.setDateHeader(HttpConstants.HEADER_LAST_MODIFIED, servletContainerStartTime);
        response.setHeader(HttpConstants.HEADER_ETAG, etag);

        PrintWriter out = response.getWriter();
        out.println(output);
    }
    
    public void handleHtc(HttpServletRequest request, HttpServletResponse response, String filePath) throws IOException
    {
        if (dynamic) {
            response.setHeader("pragma", "public");
            response.setHeader("Expires", "0");
            response.setHeader("Cache-Control", "must-revalidate, post-check=0, pre-check=0");
        }

        if (!dynamic && isUpToDate(request, filePath)) {
            response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
            return;
        }

        String output;

        synchronized (cssCache)
        {
        	output = (String) cssCache.get(filePath);
            if (output == null)
            {
                StringBuffer buffer = new StringBuffer();

                String resource = Constants.FILE_TIMS_CSS + filePath;
                InputStream raw = getClass().getResourceAsStream(resource);
                if (raw == null) {
                    throw new IOException("Failed to find resource: " + resource);
                }
                BufferedReader in = new BufferedReader(new InputStreamReader(raw));
                while (true) {
                    String line = in.readLine();
                    if (line == null) {
                        break;
                    }
                    if (dynamic) {
                        if (line.indexOf(PARAM_DEFAULT_PATH) != -1) {
                            String path = request.getContextPath() + request.getServletPath();
                            if (overridePath != null) {
                                path = overridePath;
                            }
                            line = LocalUtil.replace(line, PARAM_DEFAULT_PATH, path);
                        }
                    }

                    buffer.append(line);
                    buffer.append('\n');
                }

                output = buffer.toString();

                if (!dynamic) {
                	cssCache.put(filePath, output);
                }
            }
        }

        response.setContentType(Constants.MIME_HTC);
        response.setDateHeader(HttpConstants.HEADER_LAST_MODIFIED, servletContainerStartTime);
        response.setHeader(HttpConstants.HEADER_ETAG, etag);

        PrintWriter out = response.getWriter();
        out.println(output);
    }
    
    private boolean isUpToDate(HttpServletRequest req, String filePath)
    {
        long modifiedSince = -1;
        try {
            modifiedSince = req.getDateHeader(HttpConstants.HEADER_IF_MODIFIED);
        } 
        catch (RuntimeException ex) {
        }

        if (modifiedSince != -1) {
            modifiedSince -= modifiedSince % 1000;
        }
        String givenEtag = req.getHeader(HttpConstants.HEADER_IF_NONE);

        if (givenEtag == null) {
            if (modifiedSince > servletContainerStartTime) {
                if (log.isDebugEnabled()) {
                    log.debug("Sending 304 for " + filePath + " If-Modified-Since=" + modifiedSince + ", Last-Modified=" + servletContainerStartTime);
                }
                return true;
            }

            return false;
        }

        if (modifiedSince == -1) {
            if (!etag.equals(givenEtag)) {
                if (log.isDebugEnabled()) {
                    log.debug("Sending 304 for " + filePath + " Old ETag=" + givenEtag + ", New ETag=" + etag);
                }
                return true;
            }
            return false;
        }

        if (etag.equals(givenEtag) && modifiedSince <= servletContainerStartTime) {
            if (log.isDebugEnabled()) {
                log.debug("Sending 304 for " + filePath);
            }
            return true;
        }
        return false;
    }
}
